package com.livemeter;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


import com.livemeter.R;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;

public class InputMeterActivity extends Activity 
{
	
	static private final HashMap<String,InputMeterActivity> imas = new HashMap<String,InputMeterActivity>();
	static private final Lock ima_lock = new ReentrantLock();
	static private final Condition ima_inserted = ima_lock.newCondition();
	
	protected void signalIMA()
	{
		ima_lock.lock();
		try {
			imas.put(meter.getTitle(), this);
			Log.d("LIM-IMA","Signaling IMA");
			ima_inserted.signalAll();
		} finally {
			ima_lock.unlock();
		}
	}
	
	// Blocks until an input meter for that meter is loaded
	static public InputMeterActivity getIMA(String meterTitle)
	{
		ima_lock.lock();
		try {
			Log.d("LIM-IMA","waiting for IMA!");
			while (imas.containsKey(meterTitle) == false)
			{
				try {
					ima_inserted.await();
				} catch (InterruptedException e) {
				}
			}
			Log.d("LIM-IMA","got IMA!");
			return imas.get(meterTitle);
		} finally {
			ima_lock.unlock();
		}
	}
	
	static public Collection<InputMeterActivity> getIMAs() {return imas.values();}
	
	static public void clearIMAs() {imas.clear();}
	
	private VerticalSeekBar inputMeterControl;
	private Meter meter;
	private Dialog configureMinutesDialog;
	
    /*
     * Set captions shown above/below the meter input control.
     * */
    public void setMeterCaptions(String topCaption, String bottomCaption)
    {
    	 TextView topLabel = (TextView)findViewById(R.id.upperLabel);
    	 TextView bottomLabel = (TextView)findViewById(R.id.lowerLabel);
    	 
    	 topLabel.setText(topCaption);
    	 bottomLabel.setText(bottomCaption);
    }
    
    LIM_Event_Listener m_clientLIMEventListener = new LIM_Event_Listener() {
		@Override
		public void meterValueChanged(final LIM_MeterValueEvent evt) {
			InputMeterActivity.this.runOnUiThread(new Runnable() {
				public void run() {InputMeterActivity.this.inputMeterControl.addNewMeterValue(evt.value);}
			});
		}
		@Override
		public void tick() {
			InputMeterActivity.this.runOnUiThread(new Runnable() {
				public void run() {InputMeterActivity.this.inputMeterControl.setLastShownTime(Calendar.getInstance().getTime().getTime());}
			});
		}
		@Override
		public void pollOpened(LIM_PollEvent evt) {}
		@Override
		public void pollUpdated(LIM_PollEvent evt) {}
		@Override
		public void pollClosed(LIM_PollEvent evt) {}
		@Override
		public void meterOpened(LIM_MeterEvent evt) {}
		@Override
		public void meterClosed(LIM_MeterEvent evt) {}
		@Override
		public void questionsChanged() {}
		@Override
		public void topicStamp(final LIM_TopicStampEvent evt) 
		{
			//Log.i("IMA-TopicStamp", evt.topic.getTopicText());
			InputMeterActivity.this.runOnUiThread(new Runnable() {
	        	public void run() {inputMeterControl.addNewTopic(evt.topic);}
	        }); 
		}
		@Override
		public void setupTimeout() {}
    };
    
	/** Called when the activity is first created. */
    @SuppressWarnings("unchecked")
	@Override
    public void onCreate(Bundle savedInstanceState) 
    {  	
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.input_meter);
        
        inputMeterControl = (VerticalSeekBar)findViewById(R.id.SeekBar01);
       
        Bundle extras = getIntent().getExtras();     
          
        if (!LIM_Engine.getInstance().isClient()) //master/history cannot change local meter value
        {
        	inputMeterControl.setControlInReadOnlyMode();
        }
    	if (LIM_Engine.getInstance().isMaster())
    	{
        	inputMeterControl.setOnGraphClicked(new OnClickListener() {
            	public void onClick(View v)
            	{
            		//show poll/topic activate dialog
            		Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setClassName(InputMeterActivity.this, GroupInfoControlActivity.class.getName());
                    startActivity(intent);    
            	}
            } );
        }

        // Initialize Meter
        Object[] savedObjects = (Object[]) getLastNonConfigurationInstance(); //to load old data if only screen orientation changed
        
        if (savedObjects == null) //activity created newly 
        {
               Log.i("IMA-MeterTitle: ", extras.getString("MeterTitle") );
               meter = Meter.getMeter(extras.getString("MeterTitle"));
               this.inputMeterControl.setThumbValue(-1);
        }
        else //only screen orientation changed
        {        	
        	meter = (Meter) savedObjects[0];
        }
        
        setMeterCaptions(meter.getCaption1(),meter.getCaption2());
        
        // Initialize Meter Control
        inputMeterControl.setMax(100);
        inputMeterControl.setOnSeekBarChangeListener(new VerticalSeekBar.OnSeekBarChangeListener() {
    		@Override
    		public void onStopTrackingTouch(VerticalSeekBar seekBar) {}
    		@Override
    		public void onStartTrackingTouch(VerticalSeekBar seekBar) {}
    		@Override
    		public void onProgressChanged(VerticalSeekBar seekBar, int progress,boolean fromUser) 
    		{
    			//Log.d("current Meter Val", " " +inputMeterControl.getCurrentLocalMeterValue());
    			LIM_Engine lim = LIM_Engine.getInstance();
    			lim.client_MeterSetValue(meter.getTitle(),inputMeterControl.getThumbValue());
    		}
    	});
        
        // Load old values and restore control state before screen orientation changed
        if (savedObjects != null)
        {
        	//load old values (meter values and topics before screen orientation changed)
        	ArrayList<MeterValueVisual> listOldValues = (ArrayList<MeterValueVisual>) savedObjects[1];
        	ArrayList<Topic> listOldTopics = (ArrayList<Topic>) savedObjects[2];
        	inputMeterControl.loadOldValues(listOldValues, listOldTopics);
        	
        	String historyModeActive = savedObjects[3].toString();
        	
        	if(historyModeActive.compareToIgnoreCase("true") == 0)
        	{
           		inputMeterControl.setControlInHistoryMode();
        		inputMeterControl.setCountOfMinutesShownInGraph(Integer.parseInt(savedObjects[4].toString())); //restore scale
        	}
        }
     
        // Register LIM Event Listener
    	LIM_Engine lim = LIM_Engine.getInstance();
		lim.removeEventListener(m_clientLIMEventListener);
		lim.addEventListener(m_clientLIMEventListener);
	
		/*
        if ((meter != null) && (savedObjects == null) && (LIM_Engine.getInstance().isClient())) 
        {
    		lim.client_MeterSetValue(meter.getTitle(),(byte)inputMeterControl.getThumbValue());
        }
		*/
    }

    PowerManager.WakeLock wl = null;

    @Override
    protected void onResume() {
    	super.onResume();
    	meter.setHasBeenShown();
    	//prevent standby
        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "LIM_IMA");
        wl.acquire();
        signalIMA();
    }
    @Override
    protected void onPause() {
    	//release standby
    	wl.release();
    	super.onPause();
    }
    
    /*
     * provide options to set count of minutes shown by input meter control.
     * */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
    {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.input_meter_menu, menu);
        
        //if(this.inputMeterControl.isInHistoryMode()) //remove poll menu in history mode 
        //	menu.removeItem(R.id.pollMenu);
        
        return true;
    }
    
    /*
     * React to menu selection and change minutes shown by input meter control.
     * */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
    {
          	
    	// Handle item selection
        switch (item.getItemId()) 
        {
        case R.id.showMinutes: //select minutes for meter value control
        	this.showDialogMinuteSelection();
            break;
        case R.id.pollMenu:
        	//show polls
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setClassName(InputMeterActivity.this, GroupInfoControlActivity.class.getName());
            startActivity(intent);   
        	return true;
        case R.id.infoMenu:
        	//show splash screen
            Intent intentSplash = new Intent(Intent.ACTION_VIEW);
            intentSplash.setClassName(InputMeterActivity.this, SplashScreenActivity.class.getName());
            intentSplash.putExtra("ignoreAppConfig", true); //splash screen will be shown until user clicks
            startActivity(intentSplash);   
        	return true;
        case R.id.questionMenu:
            Intent intentQuestion = new Intent(Intent.ACTION_VIEW);
            intentQuestion.setClassName(InputMeterActivity.this, QuestionsActivity.class.getName());
            startActivity(intentQuestion);   
        	
        	return true;
        default:
            return super.onOptionsItemSelected(item);
        }
       
        return true;
    }
    
    @Override
    public Object onRetainNonConfigurationInstance() 
    {
    	//needed to keep values when screen orientation changes
    	Object[] objects = new Object[] {this.meter, this.inputMeterControl.getCloneOfAllMeterValues(), this.inputMeterControl.getCloneOfAllTopics(), 
    									 this.inputMeterControl.isInHistoryMode() ? "true" : "false", String.valueOf(this.inputMeterControl.getCountOfMinutesShownInGraph())};
        return objects;
    }
    
    /*
     * Method shows dialog for selecting the minutes shown in input meter control.
     * */
    public void showDialogMinuteSelection()
    {
    	//set up dialog
    	configureMinutesDialog = new Dialog(InputMeterActivity.this);
    	configureMinutesDialog.setContentView(R.layout.minute_selection_dialog);
        
    	configureMinutesDialog.setTitle("Minutes shown in graph");
    	configureMinutesDialog.setCancelable(true);
        
    	int minutesShown = this.inputMeterControl.getCountOfMinutesShownInGraph();
    	
    	//mark current choice in dialog
    	Spinner minutesCombobox = (Spinner) configureMinutesDialog.findViewById(R.id.msd_selectedMinutesComboBox);
    	
    	switch(minutesShown)
    	{
    		case 5: minutesCombobox.setSelection(0);
    			break;
    		case 10: minutesCombobox.setSelection(1);
			break;
    		case 15: minutesCombobox.setSelection(2);
			break;
    		case 20: minutesCombobox.setSelection(3);
			break;
			case 30: minutesCombobox.setSelection(4);
			break;
			case 45: minutesCombobox.setSelection(5);
			break;
			case 60: minutesCombobox.setSelection(6);
			break;
			case 90: minutesCombobox.setSelection(7);
			break;
    		default:
    			minutesCombobox.setSelection(0);
    			break;
    	}
    	    	
        //set up OK button of dialog
        Button okButton = (Button) configureMinutesDialog.findViewById(R.id.msd_okButton);
        
        okButton.setOnClickListener(new OnClickListener() {
        @Override
            public void onClick(View v) //OK button clicked 
        	{
        		Spinner minutesCombobox = (Spinner) configureMinutesDialog.findViewById(R.id.msd_selectedMinutesComboBox);
        	
        		int minutesSelected = 5; 
        		
        		switch(minutesCombobox.getSelectedItemPosition())
        		{
        			case 0: minutesSelected = 5;
        				break;
        			case 1: minutesSelected = 10;
        				break;
        			case 2: minutesSelected = 15;
        				break;
        			case 3: minutesSelected = 20;
        				break;
        			case 4: minutesSelected = 30;
        				break;
        			case 5: minutesSelected = 45;
        				break;
        			case 6: minutesSelected = 60;
        				break;
        			case 7: minutesSelected = 90;
        				break;
        			default:
        				minutesSelected = 5;
        				break;
        		}
        		
        		InputMeterActivity.this.inputMeterControl.setCountOfMinutesShownInGraph(minutesSelected);
        		configureMinutesDialog.dismiss();
            }
        });
            
        configureMinutesDialog.show();
    }
    
    public void beginLoading()
    {
    	inputMeterControl.beginUpdatingMeterValues();
    }
    
    public void endLoading(boolean history)
    {
    	if (history) {
    		inputMeterControl.setControlInHistoryMode();
    	} else {
    		inputMeterControl.endUpdatingMeterValues();
    	}
    }
    
    /*private void startHistoryMode()
    {
    	//TODO: remove test code here
    	// TEST History Mode 
    	Calendar c = Calendar.getInstance();
    	long millis = c.getTime().getTime() - (60 * 7 * 60 * 1000);

        inputMeterControl.beginUpdatingMeterValues();
        
        byte p10 = 0;
        byte p90 = 70;
        byte av = 50;
        byte lmv = 40;
        
     
        for(int i = 0; i < 2000; i++)
        {
        	p10+=8;
        	p90+=3;
        	av+=4;
        	lmv +=7;
        	
        	inputMeterControl.addNewMeterValue(new MeterValue(p10, p90, av, lmv, millis,));
        	
        	millis += 5000; //5 sec

        	p10+=8;
        	p90+=3;
        	av+=4;
        	lmv +=7;

        	if((i > 500 && i < 750) || (i > 1000 && i < 1250) || (i > 1500 && i < 1750))
        	{
        		p10 = 10;
        		p90 = 80;
        		av = 45;
        		lmv = 30;
        		
        	}
        	
        	if(p10 >= 100)
        		p10 = 5;
        	if(p90 >= 100)
        		p90 = 10;
        	if(av >= 100)
        		av = 40;
        	if(lmv >= 100)
        		lmv = 7;
        }
        
        inputMeterControl.setControlInHistoryMode();
    }
   	 */
}